package com.hph.demo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.GlobalEventExecutor;
import java.net.SocketAddress;

/**
 * 聊天室服务端
 * @author 10499
 */
public class NettyChatServerDemo {

    private static final ChannelGroup CHANNEL_GROUP = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    public static void main(String[] args) throws InterruptedException {

        // boss 线程池
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // worker 线程池
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // 创建服务端启动器
            ServerBootstrap bootstrap = new ServerBootstrap();
            // 对启动器进行配置
            bootstrap.group(bossGroup, workerGroup)
                    // 配置serverSocketChannel使用NioServerSocketChannel
                    .channel(NioServerSocketChannel.class)
                    // 配置多余的连接请求放置队列中
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    // socketChannel 的处理方式
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        /**
                         * 每一个socketChannel都有一个处理器pipeline
                         * @param socketChannel
                         * @throws Exception
                         */
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast("decoder", new StringEncoder());
                            pipeline.addLast("encoder", new StringDecoder());
                            pipeline.addLast(new NettySocketHandler());
                        }
                    });
            // 进行同步绑定
            ChannelFuture channelFuture = bootstrap.bind(8888).sync();
            System.out.println("服务端已启动！！！");
            // 进行同步关闭
            channelFuture.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    static class NettySocketHandler extends SimpleChannelInboundHandler<String> {

        /**
         * 客户端连接事件处理
         * @param ctx
         * @throws Exception
         */
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {

            Channel channel = ctx.channel();
            SocketAddress socketAddress = channel.remoteAddress();
            System.out.println("【客户端】 " + socketAddress + "连接成功！！！");
            if(!CHANNEL_GROUP.isEmpty()) {
                for (Channel next : CHANNEL_GROUP) {
                    next.write("欢迎 " + socketAddress + "!!!");
                    next.flush();
                }
            }
            CHANNEL_GROUP.add(channel);
        }

        /**
         * 客户端断开连接事件处理
         * @param ctx
         * @throws Exception
         */
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {

            Channel channel = ctx.channel();
            SocketAddress socketAddress = channel.remoteAddress();
            System.out.println("【客户端】 " + socketAddress + "已下线！！！");
            if(!CHANNEL_GROUP.isEmpty()) {
                for (Channel next : CHANNEL_GROUP) {
                    next.write(socketAddress + "已下线!!!");
                    next.flush();
                }
            }
            CHANNEL_GROUP.remove(channel);
        }

        /**
         * 读取数据事件处理
         * @param channelHandlerContext
         * @param msg
         * @throws Exception
         */
        @Override
        protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {

            Channel channel = channelHandlerContext.channel();
            SocketAddress socketAddress = channel.remoteAddress();
            System.out.println("【客户端】 " + socketAddress + "发送的消息：" + msg);
            if(!CHANNEL_GROUP.isEmpty()) {
                for (Channel next : CHANNEL_GROUP) {
                    next.write("【客户端】 " + socketAddress + "说：" + msg);
                    next.flush();
                }
            }
        }
    }

}
